package com.eva.cms.biz.article;

import com.eva.cms.biz.article.dto.QueryCmsArticleDTO;
import com.eva.cms.biz.article.vo.CmsArticleProfileVO;
import com.eva.cms.dao.CmsArticleMapper;
import com.eva.dao.cms.model.CmsArticleTag;
import com.eva.dao.cms.model.CmsCategory;
import com.eva.framework.common.constants.ResponseStatus;
import com.eva.framework.common.model.PageData;
import com.eva.framework.common.model.PageWrap;
import com.eva.framework.common.utils.AssertUtil;
import com.eva.framework.mp.utils.PageUtil;
import com.eva.service.cms.CmsArticleService;
import com.eva.service.cms.CmsArticleTagService;
import com.eva.service.cms.CmsCategoryService;
import com.eva.service.cms.vo.CmsArticleCategoryVO;
import com.eva.service.cms.vo.CmsArticleDetailVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CmsArticleBiz {

    @Resource
    private CmsArticleService cmsArticleService;

    @Resource
    private CmsCategoryService categoryService;

    @Resource
    private CmsArticleTagService cmsArticleTagService;

    @Resource
    private CmsArticleMapper cmsArticleMapper;

    /**
     * 文章详情
     *
     * @param uid 文章唯一标识
     * @return CmsArticleDetailVO
     */
    public CmsArticleDetailVO detail(String uid, String mode) {
        log.info("文章详情请求参数: {}", uid);
        AssertUtil.notEmpty(uid, "文章唯一标识不能为空！");
        CmsArticleDetailVO cmsArticleDetailVO = cmsArticleService.findDetail(uid, mode);
        AssertUtil.notEmpty(cmsArticleDetailVO, ResponseStatus.DATA_EMPTY);
        return cmsArticleDetailVO;
    }

    /**
     * 分页查询文章简要信息
     *
     * @param pageWrap 分页参数
     * @return 分页数据
     */
    public PageData<CmsArticleProfileVO> findProfilePage(PageWrap<QueryCmsArticleDTO> pageWrap) {
        // 查询条件补充栏目的ID值
        if (StringUtils.isNotBlank(pageWrap.getModel().getCategoryUid())) {
            CmsCategory category = categoryService.findByUid(pageWrap.getModel().getCategoryUid());
            if (category == null) {
                return PageData.empty();
            }
            pageWrap.getModel().setCategoryId(category.getId());
        }

        // 增加页容量判断，页容量最大100（防止恶意用户给定超大参数）
        if (pageWrap.getCapacity() > 100) {
            pageWrap.setCapacity(10);
        }

        // 执行查询
        PageHelper.startPage(pageWrap.getPage(), pageWrap.getCapacity());
        List<CmsArticleProfileVO> cmsArticleList = cmsArticleMapper.selectProfileList(pageWrap.getModel());
        if (CollectionUtils.isEmpty(cmsArticleList)) {
            return PageData.empty();
        }

        // 从查询的文章列表中获取栏目和标签集合，用于补充文章的栏目和标签信息
        Set<Integer> categoryIdsSet = this.getFieldIds(cmsArticleList, CmsArticleProfileVO::getCategoryIds);
        Set<Integer> tagsIdsSet = this.getFieldIds(cmsArticleList, CmsArticleProfileVO::getTagIds);
        // - 查出栏目集合并根据ID进行分组，方便补充时获取
        Map<Integer, CmsCategory> cmsCategoryMap = categoryService.findByIds(categoryIdsSet)
                .stream()
                .collect(Collectors.toMap(CmsCategory::getId, cmsCategory -> cmsCategory));
        // - 查出标签集合并根据ID进行分组，方便补充时获取
        Map<Integer, CmsArticleTag> cmsArticleTagMap = cmsArticleTagService.findByIds(tagsIdsSet)
                .stream()
                .collect(Collectors.toMap(CmsArticleTag::getId, cmsArticleTag -> cmsArticleTag));

        // 填充栏目、标签信息
        cmsArticleList.forEach(cmsArticle -> {
            cmsArticle.setCategories(this.getArticleCategories(cmsArticle.getCategoryIds(), cmsCategoryMap));
            cmsArticle.setTags(this.getArticleTags(cmsArticle.getTagIds(), cmsArticleTagMap));
        });
        return PageUtil.from(new PageInfo<>(cmsArticleList));
    }

    /**
     * 获取文章栏目集
     *
     * @param categoryIds 文章栏目ID集
     * @param categoryMap 文章栏目Map
     * @return List<CmsArticleCategoryVO>
     */
    private List<CmsArticleCategoryVO> getArticleCategories (String categoryIds, Map<Integer, CmsCategory> categoryMap) {
        if (StringUtils.isBlank(categoryIds)) {
            return Collections.emptyList();
        }
        return Arrays.stream(categoryIds.split(","))
                .filter(StringUtils::isNotBlank)
                .map(categoryId -> {
                    CmsCategory cmsCategory = categoryMap.get(Integer.valueOf(categoryId));
                    CmsArticleCategoryVO cmsArticleCategoryVO = new CmsArticleCategoryVO();
                    cmsArticleCategoryVO.setUid(cmsCategory.getUid());
                    cmsArticleCategoryVO.setTitle(cmsCategory.getTitle());
                    return cmsArticleCategoryVO;
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取文章标签集
     *
     * @param tagIds 文章标签ID集
     * @param tagMap 标签Map
     * @return List<String>
     */
    private List<String> getArticleTags (String tagIds, Map<Integer, CmsArticleTag> tagMap) {
        if (StringUtils.isBlank(tagIds)) {
            return Collections.emptyList();
        }
        return Arrays.stream(tagIds.split(","))
                .filter(StringUtils::isNotBlank)
                .map(tagId -> tagMap.get(Integer.valueOf(tagId)).getName())
                .collect(Collectors.toList());
    }

    /**
     * 获取字段中的ID集
     *
     * @param articles 文章列表
     * @param getter getter方法
     * @return Set<Integer>
     */
    private Set<Integer> getFieldIds(List<CmsArticleProfileVO> articles, Function<CmsArticleProfileVO, String> getter) {
        Set<Integer> ids = new HashSet<>();
        articles.forEach(cmsArticle -> {
            String idString = getter.apply(cmsArticle);
            if (!StringUtils.isNotBlank(idString)) {
                return;
            }
            Arrays.stream(idString.split(","))
                    .filter(StringUtils::isNotBlank)
                    .map(Integer::valueOf)
                    .forEach(ids::add);
        });
        return ids;
    }
}
